import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class XinDongGestureVerticalDragContainer extends StatefulWidget {
  final Widget child; // Widget
  final double minDragDistance; // 最短拖动距离，达到才算完成，默认88.0
  final Function()? onTap; // 单击回调
  final Function(double dragDistance, double scale)? onDragUpdate; // 拖动更新回调（拖动距离, 缩放）
  final Function(bool isDone) onDragDone; // 推动完成（是否触发完成）

  const XinDongGestureVerticalDragContainer({
    Key? key,
    required this.child,
    this.minDragDistance = 101.0,
    this.onTap,
    this.onDragUpdate,
    required this.onDragDone,
  }) : super(key: key);

  @override
  State<XinDongGestureVerticalDragContainer> createState() => _XinDongGestureVerticalDragContainerState();
}

class _XinDongGestureVerticalDragContainerState extends State<XinDongGestureVerticalDragContainer>
    with SingleTickerProviderStateMixin {
  late double _dragDistance = 0;
  late Offset _startOffset;
  late Offset _updateOffset = const Offset(0.0, 0.0);
  late Matrix4 _matrix4 = Matrix4.identity();

  late AnimationController _animationController;
  late Animation<Matrix4> _animation;

  // 计算直角三角形斜边长度
  double _getHypotenuse(double x, double y) {
    return sqrt(pow(x, 2) + pow(y, 2));
  }

  // 计算缩放比例
  double _getScale(double distance, double screenHeight) {
    return 1.0 - distance / screenHeight;
  }

  void _updateTransform(double scale, Offset offset) {
    if (!mounted) return;
    setState(() {
      _matrix4 = Matrix4.identity();
      _matrix4.translate(offset.dx, offset.dy);
      _matrix4.scale(scale, scale);
    });
    _animation = Matrix4Tween(begin: _matrix4, end: _matrix4).animate(_animationController);
  }

  void _resetTransform() {
    if (!mounted) return;
    _animation = Matrix4Tween(begin: _matrix4, end: Matrix4.identity()).animate(_animationController);
    _animation.addListener(() {
      // 回调距离
      final Matrix4 value = _animation.value;
      if (widget.onDragUpdate != null) widget.onDragUpdate!(_dragDistance, value.getMaxScaleOnAxis());
    });
    _animationController.reset();
    _animationController.forward();
    setState(() {
      _dragDistance = 0;
      _updateOffset = const Offset(0.0, 0.0);
      _matrix4 = Matrix4.identity();
    });
  }

  @override
  void initState() {
    super.initState();

    _animationController = AnimationController(duration: const Duration(milliseconds: 200), vsync: this);
    _animation = Matrix4Tween(begin: _matrix4, end: Matrix4.identity()).animate(_animationController);
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    return GestureDetector(
      onTap: widget.onTap,
      onVerticalDragStart: (DragStartDetails details) {
        _startOffset = details.globalPosition;
      },
      onVerticalDragUpdate: (DragUpdateDetails details) {
        final position = details.globalPosition;
        _dragDistance = _getHypotenuse(position.dy - _startOffset.dy, position.dx - _startOffset.dx);
        final scale = _getScale(_dragDistance, screenHeight);
        _updateOffset = Offset(_updateOffset.dx + details.delta.dx, _updateOffset.dy + details.delta.dy);
        // 更新位置缩放
        _updateTransform(scale, _updateOffset);
        // 回调距离
        if (widget.onDragUpdate != null) widget.onDragUpdate!(_dragDistance, scale);
      },
      onVerticalDragEnd: (DragEndDetails details) {
        if (_dragDistance >= widget.minDragDistance) {
          widget.onDragDone(true);
        } else {
          _resetTransform();
          widget.onDragDone(false);
        }
      },
      onVerticalDragCancel: () {
        _resetTransform();
        widget.onDragDone(false);
      },
      behavior: HitTestBehavior.opaque,
      child: AnimatedBuilder(
        animation: _animationController,
        builder: (BuildContext context, Widget? child) {
          return Transform(alignment: Alignment.center, transform: _animation.value, child: widget.child);
        },
      ),
    );
  }
}
